﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BinProtoCode
{
    class Encoder
    {
        public static string TAB1 = "    ";
        public static string TAB2 = TAB1 + TAB1;
        public static string TAB3 = TAB1 + TAB1 + TAB1;
        public static string TAB4 = TAB2 + TAB2;

        // 生成的解析函数名
        public static Dictionary<string, string> dicClientFunc = new Dictionary<string, string>();
        public static void AddClientFunc(string fileName, string funcName)
        { dicClientFunc.Add(fileName, funcName); }

        public static string GetClientFunc(string fileName)
        { return dicClientFunc[fileName]; }

        public static void RemoveClientFunc(string fileName)
        { dicClientFunc.Remove(fileName); }

        public static Dictionary<string, string> dicServerFunc = new Dictionary<string, string>();
        public static void AddServerFunc(string fileName, string funcName)
        { dicServerFunc.Add(fileName, funcName); }

        public static string GetServerFunc(string fileName)
        { return dicServerFunc[fileName]; }

        public static void RemoveServerFunc(string fileName)
        { dicServerFunc.Remove(fileName); }

        // 生成解析代码
        public static string codeClient;
        public static string codeServer;

        public static void SetClient(string strCode)
        { codeClient = strCode; }

        public static void SetServer(string strCode)
        { codeServer = strCode; }

        public static void AddClient(string strCode)
        { codeClient += strCode + Common.csRet; }

        public static void AddServer(string strCode)
        { codeServer += strCode + Common.csRet; }

        public static void AddCode(string strCode)
        {
            AddClient(strCode);
            AddServer(strCode);
        }

        public static void AddCode(string strCode, string user)
        {
            switch (user)
            {
                case Common.userAll:
                    { AddCode(strCode); }
                    break;
                case Common.userClient:
                    { AddClient(strCode); }
                    break;
                case Common.userServer:
                    { AddServer(strCode); }
                    break;
                default:
                    break;
            }
        }

        public static void AddClientReturn()
        { codeClient += Common.csRet; }

        public static void AddServerReturn()
        { codeServer += Common.csRet; }

        public static void AddReturn()
        {
            AddClientReturn();
            AddServerReturn();
        }

        public static void AddReturn(string user)
        {
            switch (user)
            {
                case Common.userAll:
                    { AddReturn(); }
                    break;
                case Common.userClient:
                    { AddClientReturn(); }
                    break;
                case Common.userServer:
                    { AddServerReturn(); }
                    break;
                default:
                    break;
            }
        }

        // 字段解析编码
        public static void EncodeFiled(string user, string type, string name, bool bConst)
        {
            if (Common.userNull == user)
            {
                AddCode("x++;");
                return;
            }

            string owner;
            if (true == bConst)
            { owner = "xList."; }
            else
            { owner = "xData."; }
            owner = TAB2 + owner;

            string strCode = "";
            switch (type.ToLower())
            {
                case "int":
                    {
                        if (true == bConst)
                        { strCode = owner + name + " = ReadInt32( 5,  x++ );"; }
                        else
                        { strCode = owner + name + " = ReadInt32( i,  x++ );"; }
                    }
                    break;
                case "intarray":
                    {
                        if (true == bConst)
                        { strCode = TAB2 + "sArray = SubString(GetString( 5,  x++ ), \';\');" + Common.csRet; }
                        else
                        { strCode = TAB2 + "sArray = SubString(GetString( i,  x++ ), \';\');" + Common.csRet; }

                        strCode += TAB2 + "foreach (string sData in sArray) {" + Common.csRet;
                        strCode += TAB3 + "if ( sData != \"\" ) { " + Common.csRet;
                        strCode += TAB2 + owner + name + ".Add(System.Convert.ToInt32(sData));" + Common.csRet;
                        strCode += TAB3 + "}" + Common.csRet;
                        strCode += TAB2 + "}" + Common.csRet;
                    }
                    break;
                case "int64":
                    {
                        if (true == bConst)
                        { strCode = owner + name + " = ReadInt64( 5,  x++ );"; }
                        else
                        { strCode = owner + name + " = ReadInt64( i,  x++ );"; }

                    }
                    break;
                case "int64array":
                    {
                        if (true == bConst)
                        { strCode = TAB2 + "sArray = SubString( GetString( 5,  x++ ) , \';\');" + Common.csRet; }
                        else
                        { strCode = TAB2 + "sArray = SubString( GetString( i,  x++ ) , \';\');" + Common.csRet; }

                        strCode += TAB2 + "foreach (string sData in sArray) {" + Common.csRet;
                        strCode += TAB3 + "if ( sData != \"\" ) { " + Common.csRet;
                        strCode += TAB2 + owner + name + ".Add(System.Convert.ToInt64(sData));" + Common.csRet;
                        strCode += TAB3 + "}" + Common.csRet;
                        strCode += TAB2 + "}" + Common.csRet;

                    }
                    break;
                case "float":
                    {
                        if (true == bConst)
                        { strCode = owner + name + " = ReadFloat( 5,  x++ );"; }
                        else
                        { strCode = owner + name + " = ReadFloat( i,  x++ );"; }
                    }
                    break;
                case "floatarray":
                    {
                        if (true == bConst)
                        { strCode = TAB2 + "sArray = SubString( GetString( 5,  x++ ) , \';\');" + Common.csRet; }
                        else
                        { strCode = TAB2 + "sArray = SubString( GetString( i,  x++ ) , \';\');" + Common.csRet; }

                        strCode += TAB2 + "foreach (string sData in sArray) {" + Common.csRet;
                        strCode += TAB3 + "if ( sData != \"\" ) { " + Common.csRet;
                        strCode += TAB2 + owner + name + ".Add(System.Convert.ToSingle(sData));" + Common.csRet;
                        strCode += TAB3 + "}" + Common.csRet;
                        strCode += TAB2 + "}" + Common.csRet;
                    }
                    break;
                case "string":
                case "stringmap":
                    {
                        if (true == bConst)
                        { strCode = owner + name + " = ReadString( 5,  x++ );"; }
                        else
                        { strCode = owner + name + " = ReadString( i,  x++ );"; }
                    }
                    break;
                case "stringarray":
                    {
                        if (true == bConst)
                        { strCode = TAB2 + "sArray = SubString( GetString( 5,  x++ ) , \';\');" + Common.csRet; }
                        else
                        { strCode = TAB2 + "sArray = SubString( GetString( i,  x++ ) , \';\');" + Common.csRet; }

                        strCode += TAB2 + "foreach (string sData in sArray) {" + Common.csRet;
                        strCode += TAB3 + "if ( sData != \"\" ) { " + Common.csRet;
                        strCode += TAB2 + owner + name + ".Add(Encoding.UTF8.GetBytes(sData));" + Common.csRet;
                        strCode += TAB3 + "}" + Common.csRet;
                        strCode += TAB2 + "}" + Common.csRet;
                    }
                    break;
                case "bool":
                    {
                        if (true == bConst)
                        { strCode = owner + name + " = ReadBool( 5,  x++ );"; }
                        else
                        { strCode = owner + name + " = ReadBool( i,  x++ );"; }
                    }
                    break;
            }
            switch (user)
            {
                case Common.userAll:
                    { AddCode(strCode); }
                    break;
                case Common.userClient:
                    {
                        AddClient(strCode);
                        AddServer("x++;");
                    }
                    break;
                case Common.userServer:
                    {
                        AddServer(strCode);
                        AddClient("x++;");
                    }
                    break;
                default:
                    { AddCode("x++;"); }
                    break;
            }
        }

        public static void EncodeSaveFile(string listName)
        {
            AddReturn();
            AddClient(TAB1 + "string fPath = System.Environment.CurrentDirectory + @\"\\dat_client\\\";");
            AddServer(TAB1 + "string fPath = System.Environment.CurrentDirectory + @\"\\dat_server\\\";");
            AddCode(TAB1 + "FileStream wFile = new FileStream(fPath + fileName + \".bytes\", FileMode.Create, FileAccess.Write);");
            AddCode(TAB1 + "Serializer.Serialize<" + listName + ">(wFile, xList);");
            AddCode(TAB1 + "wFile.Close();");
            AddReturn();

            AddCode(TAB1 + "FileStream rFile = new FileStream(fPath + fileName + \".bytes\", FileMode.Open, FileAccess.Read);");
            AddCode(TAB1 + listName + " readList = Serializer.Deserialize<" + listName + ">(rFile);");
            AddCode(TAB1 + "rFile.Close();");
            AddCode(TAB1 + "EndParse();");
            AddCode("}"); // parsefunction
            AddReturn();
        }

        // 生成解析表格数据类 输出公共代码
        public static void StartCode()
        {
            // 输出代码
            codeClient = "";

            AddCode("/**************************************************************************");
            AddCode(" *");
            AddCode(" *");
            AddCode(" *\t\t\t\t\t此文件为自动生成 不要自行更改!!!");
            AddCode(" *");
            AddCode(" *");
            AddCode(" *************************************************************************/");

            // 头文件
            AddCode("using System;");
            AddCode("using System.Reflection;");
            AddCode("using System.Text;");
            AddCode("using System.IO;");
            AddCode("using ProtoBuf;");
            AddClient("using clientdata;");
            AddServer("using serverdata;");
            AddCode("using System.Data.OleDb;");
            AddCode("using System.Data;");
            AddReturn();

            AddCode("namespace BinDataTool");
            AddCode("{");// namespace BinDataTool
            AddClient("class ClientParser");
            AddServer("class ServerParser");
            AddCode("{");// class Parser
            AddCode("// const字符串");
            AddCode("public static string strEnd = \" \\r\\n\";");
            AddCode("public static string strXlsx = \".xlsx\";");
            AddCode("public static string strDat = \".bytes\";");
            AddCode("public static string NowTime() { return DateTime.Now.ToString() + \" \"; }");
            AddReturn();

            AddCode("// Excel相关对象");
            AddCode("public static OleDbConnection gConnection;");
            AddCode("public static DataSet gSheetData;");
            AddCode("public static int nSheetIndex;");
            AddReturn();

            AddCode("// 打开工作薄");
            AddCode("public static void GetBook(string szName)");
            AddCode("{"); // GetBook
            AddCode("string source = \"Provider = Microsoft.Ace.OLEDB.12.0; Data Source = '\"+ szName + \"'; Extended Properties = 'Excel 12.0;HDR=NO;IMEX=1'\";");
            AddCode("gConnection = new OleDbConnection(source);");
            AddCode("}"); // GetBook
            AddReturn();

            AddCode("// 打开指定Worksheet");
            AddCode("public static bool GetSheet()");
            AddCode("{");
            //AddCode("gConnection.Open();");
            AddCode("string select = \"SELECT * FROM [sheet1$]\";");
            AddCode("OleDbDataAdapter readCommand = new OleDbDataAdapter(select, gConnection);");
            AddCode("gSheetData = new DataSet();");
            AddCode("readCommand.Fill(gSheetData);");
            AddCode("return true;");
            AddCode("}");
            AddReturn();

            AddCode("// 有效行数");
            AddCode("private static int _realRows = 0;");
            AddCode("// 行数");
            AddCode("public static int Rows()");
            AddCode("{ return _realRows <= 0 ? gSheetData.Tables[0].Rows.Count : _realRows;  }");
            AddReturn();

            AddCode("// 有效列数");
            AddCode("private static int _realCols = 0;");
            AddCode("// 列数");
            AddCode("public static int Cols()");
            AddCode("{ return _realCols <= 0 ? gSheetData.Tables[0].Columns.Count : _realCols; }");
            AddReturn();

            AddCode("// 分割字符串");
            AddCode("public static String[] SubString(String strData, char separator)");
            AddCode("{"); // SubString
            AddCode("String[] strArray = strData.Split(separator);");
            AddCode("return strArray;");
            AddCode("}"); // SubString
            AddReturn();

            AddCode("public static string GetString(int i, int j)");
            AddCode("{"); // GetString
            AddCode("if (null == gSheetData.Tables[0].Rows)");
            AddCode("{ return \"\"; }");
            AddCode("return gSheetData.Tables[0].Rows[i][j].ToString().Replace(\"\\n\", \"\");");
            AddCode("}"); // GetString
            AddReturn();

            AddCode("// 解析整型字段");
            AddCode("public static Int32 ReadInt32(int i, int j)");
            AddCode("{"); // ReadInt32
            AddCode("if (null == gSheetData.Tables[0].Rows)");
            AddCode("{ return 0; }");
            AddCode("string str = gSheetData.Tables[0].Rows[i][j].ToString().Replace(\"\\n\", \"\");");
            AddCode("if ( str == \"\" )");
            AddCode("return 0;");
            AddCode("return System.Convert.ToInt32(str);");
            AddCode("}"); // ReadInt32
            AddReturn();

            AddCode("// 解析Bool字段");
            AddCode("public static bool ReadBool(int i, int j)");
            AddCode("{"); // ReadBool
            AddCode("if (null == gSheetData.Tables[0].Rows)");
            AddCode("{ return false; }");
            AddCode("string str = gSheetData.Tables[0].Rows[i][j].ToString().Replace(\"\\n\", \"\");");
            AddCode("if ( str == \"\" )");
            AddCode("return false;");
            AddCode("string stu = str.Trim().ToUpper();");
            AddCode("if (stu.Equals(\"FALSE\") || stu.Equals(\"0\") || stu.Equals(\"假\")) { return false; }"); // ReadBool
            AddCode("return true;");
            AddCode("}");
            AddReturn();

            AddCode("public static Int64 ReadInt64(int i, int j)");
            AddCode("{"); // Readint64
            AddCode("if (null == gSheetData.Tables[0].Rows)");
            AddCode("{ return 0; }");
            AddCode("string str = gSheetData.Tables[0].Rows[i][j].ToString().Replace(\"\\n\", \"\");");
            AddCode("if ( str == \"\" )");
            AddCode("return 0;");
            AddCode("return System.Convert.ToInt64(str);");
            AddCode("}"); // ReadInt64
            AddReturn();

            AddCode("// 解析float");
            AddCode("public static float ReadFloat(int i, int j)");
            AddCode("{"); // ReadFloat
            AddCode("if (null == gSheetData.Tables[0].Rows)");
            AddCode("{ return 0; }");
            AddCode("string str = gSheetData.Tables[0].Rows[i][j].ToString().Replace(\"\\n\", \"\");");
            AddCode("if ( str == \"\" )");
            AddCode("return 0;");
            AddCode("return System.Convert.ToSingle(str);");
            AddCode("}"); // ReadFloat
            AddReturn();

            AddCode("// 解析字符串");
            AddCode("public static byte[] ReadString(int i, int j)");
            AddCode("{"); // ReadString
            AddCode(TAB1 + "object element = gSheetData.Tables[0].Rows[i][j];");
            AddCode(TAB1 + "if (null == element)");
            AddCode(TAB1 + "{ return Encoding.UTF8.GetBytes(\"\"); }");
            AddCode(TAB1 + "return Encoding.UTF8.GetBytes(element.ToString().Replace(\"\\n\", \"\"));");
            AddCode("}"); // ReadString
            AddReturn();

            AddCode("// 开始解析Excel");
            AddCode("private static void StartParse(string path)");
            AddCode("{"); // StartParse
            AddCode(TAB1 + "nSheetIndex = 1;");
            AddCode(TAB1 + "GetBook(MeFile.GetFilePath(path));");
            AddCode(TAB1 + "GetSheet();");

            AddCode(TAB1 + "//init real rows");
            AddCode(TAB1 + "for (int i = 0; i < gSheetData.Tables[0].Rows.Count; i++) {");
            AddCode(TAB2 + "if (gSheetData.Tables[0].Rows[i][0].ToString().Trim().Equals(\"__END__\")) {");
            AddCode(TAB3 + "_realRows = i;");
            AddCode(TAB3 + "break;");
            AddCode(TAB2 + "}");
            AddCode(TAB1 + "}");

            AddCode(TAB1 + "//init real columns");
            AddCode(TAB1 + "for (int j = 0; j < gSheetData.Tables[0].Columns.Count; j++) {");
            AddCode(TAB2 + "if (gSheetData.Tables[0].Rows[0][j].ToString().Trim().Equals(\"__END__\")) {");
            AddCode(TAB3 + "_realCols = j;");
            AddCode(TAB3 + "break;");
            AddCode(TAB2 + "}");
            AddCode(TAB1 + "}");

            AddCode("}"); // StartParse
            AddReturn();

            AddCode("// 结束解析Excel");
            AddCode("public static void EndParse()");
            AddCode("{"); // EndParse
            AddCode(TAB1 + "nSheetIndex = 1;");
            AddCode(TAB1 + "gConnection = null;");
            AddCode(TAB1 + "gSheetData = null;");
            AddCode(TAB1 + "_realRows = 0;");
            AddCode(TAB1 + "_realCols = 0;");

            AddCode("}"); // EndParse
            AddReturn();
        }

        public static void EndCode()
        {
            AddClient("public static void ParseClient(string fileName)");
            AddServer("public static void ParseServer(string fileName)");
            AddCode("{"); // Parse
            AddCode("if ( fileName.Contains( \"$\" ) )");
            AddCode("{ return; }");

            AddCode("switch (fileName)");
            AddCode("{"); // switch 

            foreach (KeyValuePair<string, string> kvp in dicClientFunc)
            {
                AddClient("case \"" + kvp.Key + "\":");
                AddClient("{" + kvp.Value + "( fileName ); }");
                AddClient("break;");
            }

            foreach (KeyValuePair<string, string> kvp in dicServerFunc)
            {
                AddServer("case \"" + kvp.Key + "\":");
                AddServer("{" + kvp.Value + "( fileName ); }");
                AddServer("break;");
            }

            AddCode("default:");
            AddCode("break;");
            AddCode("}"); // switch 
            AddCode("}"); // Parse

            AddCode("}"); // class Parser
            AddCode("}"); // namespace BinDataTool

            string path = System.Environment.CurrentDirectory + @"\..\\Code\\tool\\BinDataTool\\BinDataTool\\ClientParser.cs";

            byte[] cData = Encoding.UTF8.GetBytes(codeClient);
            FileStream cFile = new FileStream(path, FileMode.Create, FileAccess.Write);
            cFile.Write(cData, 0, cData.Length);
            cFile.Close();

            path = System.Environment.CurrentDirectory + @"\..\\Code\tool\BinDataTool\BinDataTool\ServerParser.cs";

            byte[] sData = Encoding.UTF8.GetBytes(codeServer);
            FileStream sFile = new FileStream(path, FileMode.Create, FileAccess.Write);
            sFile.Write(sData, 0, sData.Length);
            sFile.Close();
        }
    }
}
